package com.quad.innovators.salesease.interceptor;


import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.quad.innovators.salesease.cache.UserTokenCache;
import com.quad.innovators.salesease.common.result.Result;
import com.quad.innovators.salesease.config.property.LoginInfoConfig;
import com.quad.innovators.salesease.constants.SecurityConstants;
import com.quad.innovators.salesease.context.UserContext;
import com.quad.innovators.salesease.enums.ResultCode;
import com.quad.innovators.salesease.model.dto.SysUserAuthInfo;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    private final UserTokenCache userTokenCache;
    private final LoginInfoConfig loginInfoConfig;

    public LoginInterceptor(UserTokenCache userTokenCache, LoginInfoConfig loginInfoConfig) {
        this.userTokenCache = userTokenCache;
        this.loginInfoConfig = (LoginInfoConfig) loginInfoConfig.clone();
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean checkedHeader = checkHeader(request, response);
        boolean checkedCookie = checkCookie(request, response);
        if(checkedHeader || checkedCookie) {
            return true;
        }
        log.error("cookie is null. 请求的uri-->{}:{}", request.getMethod(), request.getRequestURI());
        response.addHeader("Content-Type", "application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().write(JSON.toJSONString(Result.otherErr(ResultCode.NO_LOGIN)));
        return false;
    }


    /**
     * 检查请求头是否包含认证
     * @param request 请求
     * @param response 相应
     * @return 是否包含
     */
    private boolean checkHeader(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (StrUtil.isBlank(token) || !token.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            return false;
        }
        // 去除 Bearer 前缀
        token = token.substring(SecurityConstants.TOKEN_PREFIX.length());
        if(StringUtils.isNotBlank(token) && userTokenCache.exists(token)){
            bindUserInfo(request, response, token);
            return true;
        }
        return false;
    }

    /**
     * 检查cookie是否包含信息
     * @param request 请求
     * @param response 相应
     * @return 结果
     */
    private boolean checkCookie(HttpServletRequest request, HttpServletResponse response){
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            return false;
        }
        for (Cookie cookie : cookies) {
            if (!StringUtils.equals(cookie.getName(), HttpHeaders.AUTHORIZATION)) {
                continue;
            }
            String token = cookie.getValue();
            token = token.substring(SecurityConstants.TOKEN_PREFIX.length());
            if (StringUtils.isNotBlank(token) && userTokenCache.exists(token)) {
                bindUserInfo(request,response, token);
                return true;
            }
        }
        return false;
    }


    /**
     * 绑定用户信息
     * @param request 请求
     * @param response 相应
     * @param token token
     */
    private void bindUserInfo(HttpServletRequest request, HttpServletResponse response,String token){
        SysUserAuthInfo sysUserAuthInfo = userTokenCache.expire(token, loginInfoConfig.getTokenTimeout());
        refreshCookie(request, response, loginInfoConfig.getTokenTimeout());
        bindToken2Session(request, token);
        UserContext.setCurrentUser(sysUserAuthInfo);
    }

    /**
     * 绑定token到session，后续可以从session里面取
     * @param request 请求
     * @param token token
     */
    private void bindToken2Session(HttpServletRequest request, String token) {
        HttpSession session = request.getSession();
        session.setAttribute(HttpHeaders.AUTHORIZATION, token);
    }


    /**
     * 刷新cookie
     *
     * @param request 请求
     * @param response 响应
     * @param tokenTimeout 超时
     */
    private void refreshCookie(HttpServletRequest request, HttpServletResponse response, Long tokenTimeout) {
        Cookie[] cookies = request.getCookies();
        Cookie update;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (StringUtils.equals(cookie.getName(), HttpHeaders.AUTHORIZATION)) {
                    update = new Cookie(cookie.getName(), cookie.getValue());
                    update.setPath("/");
                    update.setDomain(loginInfoConfig.getCookieDomain());
                    update.setMaxAge(Math.toIntExact(tokenTimeout));
                    update.setHttpOnly(true);
                    response.addCookie(update);
                }
            }
        }
    }
}
